10 #define forn(i, n) for (int i = 0; i < (n); i++)
11 #define TOLERANCIA 1e-8
19 MaybeDouble(long double v
, bool b
): valor(v
), valido(b
) {};
26 Vector(long double xi
, long double yi
): x(xi
), y(yi
) {};
32 long double angulo() {
42 Columna(long double x
, long double y
, long double r
) : posicion(x
,y
), radio(r
) {};
45 typedef Vector Lampara
;
46 typedef pair
<long double, long double> Intervalo
;
47 typedef pair
<Vector
, Vector
> Segmento
;
50 inline long double largo(const Segmento
& s
) {
51 return Vector(s
.second
.x
- s
.first
.x
, s
.second
.y
- s
.first
.y
).norma();
54 inline long double largo(const Intervalo
& i
) {
55 assert(i
.first
<= i
.second
);
56 return i
.second
- i
.first
;
60 MaybeDouble
intersect_segments(const Segmento
& s1
, const Segmento
& s2
) {
62 Vector p2
= s1
.second
;
64 Vector p4
= s2
.second
;
66 long double den
= (p4
.y
-p3
.y
)*(p2
.x
-p1
.x
) - (p4
.x
-p3
.x
)*(p2
.y
-p1
.y
);
68 long double ua_num
= (p4
.x
-p3
.x
)*(p1
.y
-p3
.y
) - (p4
.y
-p3
.y
)*(p1
.x
-p3
.x
);
69 long double ub_num
= (p2
.x
-p1
.x
)*(p1
.y
-p3
.y
) - (p2
.y
-p1
.y
)*(p1
.x
-p3
.x
);
71 if (fabs(den
) < TOLERANCIA
) {
72 // Caso en que los segmentos son paralelos
73 if (fabs(ua_num
- ub_num
) < TOLERANCIA
&& fabs(ub_num
) < TOLERANCIA
) {
74 // Las rectas son coincidentes, esto no deberia ocurrir
76 return MaybeDouble((p1
.norma() > p2
.norma()? 0 : 1), true);
78 return MaybeDouble(0, false);
81 if (ub_num
/den
>= 0) {
82 return MaybeDouble(ua_num
/den
, true);
84 return MaybeDouble(0, false);
88 Intervalo
interseccion_intervalos(const Intervalo
& i1
, const Intervalo
& i2
) {
90 long double d0
= max(i1
.first
, i2
.first
);
91 long double d1
= min(i1
.second
, i2
.second
);
94 return Intervalo(0, 0);
96 return Intervalo(d0
, d1
);
101 Intervalo
rango_oscurecido(const Segmento
& pared
, const Lampara
& lampara
, const Columna
& columna
) {
102 Vector
bisectriz(columna
.posicion
.x
- lampara
.x
, columna
.posicion
.y
- lampara
.y
);
103 long double p
= asin(columna
.radio
/bisectriz
.norma());
104 long double alpha
= bisectriz
.angulo();
106 Vector
d1(cos(alpha
+ p
), sin(alpha
+ p
));
107 Vector
d2(cos(alpha
- p
), sin(alpha
- p
));
109 MaybeDouble p1
= intersect_segments(pared
, Segmento(lampara
, Vector(lampara
.x
+ d1
.x
, lampara
.y
+ d1
.y
)));
110 MaybeDouble p2
= intersect_segments(pared
, Segmento(lampara
, Vector(lampara
.x
+ d2
.x
, lampara
.y
+ d2
.y
)));
112 long double unidad
= largo(pared
);
114 // Se sabe que los puntos de interseccion estan ordenados correctamente
115 // porque el angulo de diferencia entre las semirectas es menor a 180,
116 // entonces no es necesario chequearlo.
121 return Intervalo(0, 0);
123 res
= Intervalo(0, p2
.valor
);
127 res
= Intervalo(p1
.valor
, 1);
129 res
= Intervalo(p1
.valor
, p2
.valor
);
133 res
= interseccion_intervalos(res
, Intervalo(0,1));
134 return Intervalo(res
.first
* unidad
, res
.second
* unidad
);
137 void invertir_rango(const list
<Intervalo
>& ints
, long double fin
, list
<Intervalo
>& out
) {
140 out
.push_back(Intervalo(0,fin
));
145 list
<Intervalo
>::const_iterator it
= ints
.begin();
147 out
.push_back(Intervalo(0, it
->first
));
152 list
<Intervalo
>::const_iterator itprev
= ints
.begin();
153 while (it
!= ints
.end()) {
154 out
.push_back(Intervalo(itprev
->second
, it
->first
));
159 if (itprev
->second
< fin
) {
160 out
.push_back(Intervalo(itprev
->second
, fin
));
165 void reduce_union(list
<Intervalo
>& l_o
, list
<Intervalo
>& out
) {
166 // elimino repetidos para acelerar el sort
169 for (list
<Intervalo
>::const_iterator itcito
= l_o
.begin(); itcito
!= l_o
.end(); itcito
++) {
170 if (itcito
->first
< itcito
->second
) {
171 l
.push_back(Intervalo(itcito
->first
, itcito
->second
));
172 } else if (itcito
->first
> itcito
->second
) {
178 if (!l
.size()) return;
182 list
<Intervalo
>::const_iterator it
= l
.begin();
183 Intervalo cand
= *it
;
187 while (it
!= l
.end()) {
189 if (otro
.first
< otro
.second
) {
190 if (otro
.first
> cand
.second
) {
194 if (otro
.second
> cand
.second
) {
195 cand
= Intervalo(cand
.first
, otro
.second
);
206 long double resolver(const list
<Lampara
>& lamparas
, const list
<Columna
>& columnas
, int max_x
, int max_y
) {
207 list
<Segmento
> paredes
;
208 paredes
.push_back(Segmento(Vector(0,0), Vector(0, max_y
)));
209 paredes
.push_back(Segmento(Vector(0,max_y
), Vector(max_x
, max_y
)));
210 paredes
.push_back(Segmento(Vector(max_x
,max_y
), Vector(max_x
, 0)));
211 paredes
.push_back(Segmento(Vector(max_x
,0), Vector(0, 0)));
213 long double total
= 0;
215 for (list
<Segmento
>::iterator p
= paredes
.begin(); p
!= paredes
.end(); p
++) {
216 list
<Intervalo
> luces_pared
;
217 for (list
<Lampara
>::const_iterator l
= lamparas
.begin(); l
!= lamparas
.end(); l
++) {
218 list
<Intervalo
> zonas_tapadas
;
219 for (list
<Columna
>::const_iterator c
= columnas
.begin(); c
!= columnas
.end(); c
++) {
220 zonas_tapadas
.push_back(rango_oscurecido(*p
, *l
, *c
));
223 list
<Intervalo
> tapadas_unidas
;
224 list
<Intervalo
> zona_iluminada
;
226 reduce_union(zonas_tapadas
, tapadas_unidas
);
227 invertir_rango(tapadas_unidas
, largo(*p
), zona_iluminada
);
229 luces_pared
.splice(luces_pared
.end(), zona_iluminada
);
232 list
<Intervalo
> luces_pared_unidas
;
233 reduce_union(luces_pared
, luces_pared_unidas
);
235 for (list
<Intervalo
>::iterator it
= luces_pared_unidas
.begin(); it
!= luces_pared_unidas
.end(); it
++) {
246 int nl
, nc
, max_x
, max_y
;
249 scanf("%d %d %d %d", &nl
, &nc
, &max_x
, &max_y
);
251 if (!(nl
|| nc
|| max_x
|| max_y
)) {
255 list
<Vector
> lamparas
;
256 list
<Columna
> columnas
;
261 scanf("%d %d", &x
, &y
);
262 lamparas
.push_back(Lampara(x
,y
));
266 scanf("%d %d %d", &x
, &y
, &r
);
267 columnas
.push_back(Columna(x
, y
, r
));
270 printf("%.4Lf\n", resolver(lamparas
, columnas
, max_x
, max_y
));